/*
 * msgbox.h
 *
 *  Created on: Jul 22, 2013
 *      Author: g.kruglov
 */

#ifndef MSGBOX_H_
#define MSGBOX_H_

#include "ch.h"
#include <string.h>
#include "kl_lib_L15x.h"

struct CcidHeader_t {
    uint8_t bMessageType;
    uint32_t dwLength;
    uint8_t bSlot;
    uint8_t bSeq;
    union {
        struct {
            uint8_t bBWI;
            uint16_t wLevelParameter;
        } __attribute__ ((__packed__));
        struct {
            uint8_t bStatus;
            uint8_t bError;
            union {
                uint8_t bChainParameter;    /* Rdr_to_PC_DataBlock */
                uint8_t bClockStatus;       /* RDR_to_PC_SlotStatus */
                uint8_t bProtocolNum;       /* RDR_to_PC_Parameters */
            } __attribute__ ((__packed__));
        } __attribute__ ((__packed__));
    } __attribute__ ((__packed__));
} __attribute__ ((__packed__));

// =========================== Crd-CCID messages ===============================
/*
 * All messages from CCID to Card are PC_TO_RDR.
 * All replies  from Card to CCID are same PC_TO_RDR
 * All messages from CCID to CCID are RDR_TO_PC
 */
struct ccMsg_t {
    CcidHeader_t Hdr;
    uint8_t *PData;
};

// =============================== Message Box =================================
template <typename T, int32_t Sz>
class MsgBox_t {
private:
    Mailbox imailbox;
    msg_t IMsgBuf[Sz];
    T IBuf[Sz], *pw;
public:
    void Init() {
        pw = IBuf;
        chMBInit(&imailbox, IMsgBuf, Sz);
    }

    uint8_t Post(T Obj) {
        uint8_t rslt=OK;
        chSysLock();
        if(chMBGetUsedCountI(&imailbox) >= Sz) rslt = FAILURE; // No empty slots
        chSysUnlock();
        if(rslt != OK) return rslt;
        memcpy(pw, &Obj, sizeof(T));
        rslt = (chMBPost(&imailbox, (msg_t)pw, TIME_INFINITE) == RDY_OK)? OK : FAILURE;
//        Uart.Printf("MsgBox %d\r", rslt);
        if(pw == &IBuf[Sz-1]) pw = IBuf;    // Circulate buffer
        else pw++;
        return rslt;
    }

    void FetchMsg(T *Ptr) {
        msg_t msg;
        while(chMBFetch(&imailbox, &msg, TIME_INFINITE) != RDY_OK);
        memcpy(Ptr, (T*)msg, sizeof(T));

    }

    uint8_t TryFetchMsg(T *Ptr) {
        msg_t msg;
        if(chMBFetch(&imailbox, &msg, 9) == RDY_OK) {
            memcpy(Ptr, (T*)msg, sizeof(T));
            return OK;
        }
        else return FAILURE;
    }
};


#endif /* MSGBOX_H_ */
